<template>
  <div class="overflow-auto">
    <div class="tree-table" :style="`min-width:${treeMinWidth}px;`">
      <!-- 标题行 -->
      <div class="row no-wrap tree-table-row">
        <div class="q-pl-lg tree-table-cell">{{ title }}</div>
        <q-space />
        <div class="row no-wrap self-stretch">
          <template v-for="col in columns" :key="col.name">
            <q-separator vertical />
            <div class="tree-table-cell" :class="col.headerClasses" :style="getStyle(col, 'header')">
              <slot :name="'col-' + col.name" :column="col"> {{ col.label }} </slot>
            </div>
          </template>
        </div>
      </div>
      <!-- 加载条 -->
      <q-linear-progress v-if="loading" indeterminate size="xs" color="grey-8" />

      <!-- 树结构 -->
      <q-tree
        :nodes="nodes"
        :node-key="nodeKey"
        :label-key="labelKey"
        :children-key="childrenKey"
        :tick-strategy="tickStrategy"
        :accordion="accordion"
        :ticked="ticked"
        :expanded="expanded"
        :selected="selected"
        :filter="filter"
        :filter-method="filterMethod"
        :default-expand-all="defaultExpandAll"
        :no-transition="noTransition"
        @update:ticked="(v) => emit('update:ticked', v)"
        @update:expanded="(v) => emit('update:expanded', v)"
        @update:selected="(v) => emit('update:selected', v)"
      >
        <template #default-header="{ node, ticked: hTicked, expanded: hExpanded }">
          <slot name="tree" :ticked="hTicked" :expanded="hExpanded" :node="node"> &nbsp;{{ node[labelKey] }} &nbsp; </slot>

          <q-space />

          <!-- 单元格,div 模拟 -->
          <div class="row no-wrap self-stretch tree-table-row">
            <template v-for="col in columns" :key="col.name">
              <q-separator vertical />
              <div class="tree-table-cell" :class="col.classes" :style="getStyle(col, 'cell')">
                <slot :name="'cell-' + col.name" :ticked="hTicked" :expanded="hExpanded" :node="node">
                  {{ getValue(col, node) }}
                </slot>
              </div>
            </template>
          </div>
        </template>
      </q-tree>
    </div>
  </div>
</template>

<script lang="ts" setup>
  import { computed } from 'vue';
  import { QTreeNode } from 'quasar';
  import { getPropertyFromItem } from 'src/utils';

  interface Props {
    //tree attr
    nodes: QTreeNode[];
    nodeKey?: string;
    labelKey?: string;
    childrenKey?: string;
    tickStrategy?: 'none' | 'strict' | 'leaf' | 'leaf-filtered' | undefined;
    ticked?: [] | undefined;
    expanded?: [] | undefined;
    selected?: [] | undefined;
    filter?: string;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    filterMethod?: (node: any, filter: string) => boolean;
    accordion?: boolean;
    defaultExpandAll?: boolean;
    noTransition?: boolean;
    // data
    columns: TableColumn[];
    loading?: boolean;
    title?: string;
  }

  const props = withDefaults(defineProps<Props>(), {
    nodeKey: 'value',
    labelKey: 'label',
    childrenKey: 'children',
    tickStrategy: 'none',
    ticked: undefined,
    expanded: undefined,
    selected: undefined,
    filter: undefined,
    filterMethod: undefined,
    // data
    title: undefined,
    loading: false,
  });

  const emit = defineEmits(['update:ticked', 'update:expanded', 'update:selected']);

  // 整体的最小宽度，保证有tree显示的空间，空间不够添加滚动
  const treeMinWidth = computed(() => {
    const colWidths = props.columns.map((a) => ((a.width ?? 0) == 0 ? 100 : a.width!));
    const colTotal = colWidths.reduce((n, m) => n + m);
    // 树至少230的宽度
    return colTotal + 230;
  });

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  function getValue(col: TableColumn, node: any) {
    const val = getPropertyFromItem(node, col.field);
    return col.format ? col.format(val, node) : val;
  }

  function getStyle(col: TableColumn, type: 'header' | 'cell'): string {
    var style = (type == 'header' ? col.headerStyle : (col.style as string)) ?? '';
    if (style != '' && !style.endsWith(';')) style += ';';
    // 宽度必须用固定值，不能用最大最小，不然每行不一致,会错位显示，把min,max都换成width
    style = style.replace(/min-width/g, 'width').replace(/max-width/g, 'width');
    // 在最后面添加一个width，vue计算时会只取这一个
    style += 'width:' + ((col.width ?? 0) == 0 ? 100 : col.width) + 'px;';

    // 对齐方式
    const align = col.align ?? 'center';
    style += `text-align:${align};`;
    if (align != 'center') {
      style += `padding-${align}:10px;`;
    }
    return style;
  }
</script>

<style lang="scss" scoped>
  :deep(.q-tree__node-header) {
    margin-top: 0;
    padding: 0 0 0 4px;
  }
  :deep(.q-tree__node) {
    border-top: solid 1px rgba(0, 0, 0, 0.12);
    padding-bottom: 0;
  }
  .tree-table {
    width: 100%;
    border: solid 1px rgba(0, 0, 0, 0.12);
    font-size: 15px;

    &-row {
      min-height: 50px;
    }
    &-cell {
      word-wrap: break-word;
      margin: auto;
    }
  }
</style>
